package ioc

import (
	"gitee.com/huanminabc/go-utils/container"
	"gitee.com/huanminabc/go-utils/reflect_extend"
	"reflect"
)

func Provides(param ...interface{}) {
	for _, p := range param {
		Provide(p)
	}
}

// 创建注入
func Provide(param interface{}) {
	if param == nil {
		panic("param is nil")

	}
	var newParam = param
	//判断是否是指针
	if reflect_extend.IsPtr(param) {
		param = reflect_extend.GetPtrValue(param)
	}
	var kind reflect.Kind
	var defName string
	if param == nil { //表示是空指针 ,指针地址里面是空的
		param = newParam
		kind = reflect.TypeOf(newParam).Elem().Kind()
	} else {
		kind = reflect.TypeOf(param).Kind()
		defName = reflect_extend.GetDefFullName(param)
	}

	switch kind {
	case reflect.Func:
		funInject(defName, param)
	case reflect.Struct:
		if !reflect_extend.IsPtr(newParam) {
			panic("param必须是结构体指针")
		}
		structInject(defName, param, newParam)
	case reflect.Interface:
		if !reflect_extend.IsPtr(newParam) {
			panic("param必须是接口指针")
		}
		injectInterface(newParam)
	default:
		panic("不支持的类型")
	}
}

func injectInterface(inter interface{}) {
	//判断interface是否是指针
	if !reflect_extend.IsPtr(inter) {
		panic("inter必须是指针 ,可以使用new(接口)创建")
	}
	getTypeInjectMap := GetTypeInjectMap()
	for _, valueImpl := range getTypeInjectMap {
		//判断
		if reflect_extend.IsImplement(valueImpl.Content, inter) {
			name := reflect_extend.GetDefFullName(inter)
			if v, ok := interfaceInjectMap[name]; ok {
				v.Add(valueImpl)
			} else {
				set := container.NewSet[*InjectEntity]()
				set.Add(valueImpl)
				interfaceInjectMap[name] = set
			}
		}
	}
}

func structInject(defName string, notPtr interface{}, ptr interface{}) {
	inject := InjectEntity{
		Type:       reflect.Struct,
		Content:    ptr,
		Name:       defName,
		ReturnType: reflect.TypeOf(notPtr),
	}
	addInject(inject)
}

// fun 是函数定义
func funInject(defName string, fun interface{}) {
	inject := InjectEntity{
		Type:    reflect.Func,
		Content: fun,
		Name:    defName,
	}
	retType := reflect_extend.GetFuncRetType(fun)
	//如果函数返回值是多个,则不支持
	if len(retType) > 1 && len(retType) != 0 {
		panic("函数返回值不能多个,或者没有返回值")
	}
	var res reflect.Type
	//判断是否是指针
	if retType[0].Kind() == reflect.Ptr && retType[0].Elem().Kind() == reflect.Struct {
		res = retType[0].Elem()
	}
	//返回值必须是结构体
	if retType[0].Kind() == reflect.Struct {
		res = retType[0]
	}

	//如果 res 为空,则不符合规则
	if res == nil {
		panic("New函数的返回值必须是结构体")
	}

	inject.IsNewFunc = true
	inject.ReturnType = res
	addInject(inject)
	return

}
